#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <pthread.h>


// Implementation w/o BigNumbers
// When p is inf, stop calculating it

// Number of iterations
#define N 1000000
#define PRINT_PRECISION 6
#define NUM_THREADS	1

typedef struct thread_data{
	void *arg1;
	void *arg2;
	void *arg3;
}thread_data;

void *calcB(void *threadArg){
	thread_data *data = (thread_data *) threadArg;

	double *saveVar = (double *)data->arg1;
	double *var1 = (double *)data->arg2;
	double *var2 = (double *)data->arg3;

	*saveVar = sqrt(*var1 * *var2);

	return NULL;
}


int main(int argc, char const *argv[]){

	int i;

	pthread_t thread[NUM_THREADS];
    pthread_attr_t attr;

	double aCur, aLast = 1.0;
	double bCur, bLast = sqrt(2.0)/2.0;
	double tCur = 0.25;
	double pCur = 1.0;

	bool pInf = false;

	void *status;

	thread_data td1;
	td1.arg1 = &bCur;
	td1.arg2 = &aLast;
	td1.arg3 = &bLast;

	// Initialize and set thread detached attribute
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

	for (int i = 0; i < N; ++i){

		// Calculate new b
		pthread_create(&thread[0], &attr, calcB, (void *)&td1);

		// Calculate new a
		aCur = (aLast + bLast)/2;

		// Calculate new p if p is not Inf yet
		if(!pInf){
			pCur*=2;
			if(isinf(pCur)){
				pInf = true;
				pCur = 0;
			}
		}


		// Calculate new t
		tCur = tCur - pCur*(aLast - aCur)*(aLast - aCur);

		// Wait threads to finish
		pthread_join(thread[0], &status);

		// Save variables for next iteration
		aLast = aCur;
		bLast = bCur;
	}


   	pthread_attr_destroy(&attr);

	printf("a = %lf\nb = %lf\nt = %lf\np = %lf\n", aCur, bCur, tCur, pCur);

	// Print PI
	printf("%.*lf\n", PRINT_PRECISION, ((aCur + bCur)*(aCur + bCur))/(4*tCur));

	return 0;
}